From 3814d075cb7306f111bfa41f10b7d719d08b2679 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 31 Aug 2018 19:44:22 +0530 Subject: [PATCH] lib/repo: Ensure min-free-space* config value doesn't overflow when converted to bytes In a subsequent commit, we add a public API to read the value of min-free-space-* value in bytes. The value for free space check is enforced in terms of block size instead of bytes. Therefore, for consistency we check while preparing the transaction that the value doesn't overflow when converted to bytes. https://phabricator.endlessm.com/T23694 Closes: #1715 Approved by: cgwalters --- src/libostree/ostree-repo-commit.c | 28 +++++++++++++++++++--------- src/libostree/ostree-repo-private.h | 1 + 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index d464cd0a..1336d282 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -1536,23 +1536,28 @@ devino_cache_lookup (OstreeRepo *self, return dev_ino_val->checksum; } -static guint64 -min_free_space_calculate_reserved_blocks (OstreeRepo *self, struct statvfs *stvfsbuf) +static gboolean +min_free_space_calculate_reserved_blocks (OstreeRepo *self, struct statvfs *stvfsbuf, GError **error) { - guint64 reserved_blocks = 0; + self->reserved_blocks = 0; if (self->min_free_space_mb > 0) { - reserved_blocks = (self->min_free_space_mb << 20) / stvfsbuf->f_bsize; + if (self->min_free_space_mb > (G_MAXUINT64 >> 20) || + self->txn.blocksize > (1 << 20)) + return glnx_throw (error, "min-free-space value is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes", + G_MAXUINT64 / stvfsbuf->f_bsize); + + self->reserved_blocks = (self->min_free_space_mb << 20) / self->txn.blocksize; } else if (self->min_free_space_percent > 0) { /* Convert fragment to blocks to compute the total */ guint64 total_blocks = (stvfsbuf->f_frsize * stvfsbuf->f_blocks) / stvfsbuf->f_bsize; - reserved_blocks = ((double)total_blocks) * (self->min_free_space_percent/100.0); + self->reserved_blocks = ((double)total_blocks) * (self->min_free_space_percent/100.0); } - return reserved_blocks; + return TRUE; } /** @@ -1650,11 +1655,16 @@ ostree_repo_prepare_transaction (OstreeRepo *self, g_mutex_lock (&self->txn_lock); self->txn.blocksize = stvfsbuf.f_bsize; - guint64 reserved_blocks = min_free_space_calculate_reserved_blocks (self, &stvfsbuf); + if (!min_free_space_calculate_reserved_blocks (self, &stvfsbuf, error)) + { + g_mutex_unlock (&self->txn_lock); + return FALSE; + } + /* Use the appropriate free block count if we're unprivileged */ guint64 bfree = (getuid () != 0 ? stvfsbuf.f_bavail : stvfsbuf.f_bfree); - if (bfree > reserved_blocks) - self->txn.max_blocks = bfree - reserved_blocks; + if (bfree > self->reserved_blocks) + self->txn.max_blocks = bfree - self->reserved_blocks; else { self->cleanup_stagedir = TRUE; diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 99eaf494..3cc4aba0 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -153,6 +153,7 @@ struct OstreeRepo { gid_t target_owner_gid; guint min_free_space_percent; /* See the min-free-space-percent config option */ guint64 min_free_space_mb; /* See the min-free-space-size config option */ + guint64 reserved_blocks; gboolean cleanup_stagedir; guint test_error_flags; /* OstreeRepoTestErrorFlags */ -- 2.30.2